#pragma once

#include <chrono>
#include <random>


namespace Random {
    inline std::mt19937 generate() {
        std::random_device rd {};

        std::seed_seq ss {
            static_cast<std::seed_seq::result_type>(std::chrono::steady_clock::now().time_since_epoch().count()),
            rd(),
            rd(),
            rd(),
            rd(),
            rd(),
            rd(),
            rd(),
        };

        return std::mt19937 {ss};
    }

    inline std::mt19937 mt { generate() };

    inline int get(int min, int max) {
        return std::uniform_int_distribution{min, max}(mt);
    }

    template <typename T>
    T get(T min, T max) {
        return std::uniform_int_distribution{min, max}(mt);
    }

    template <typename R,  typename S, typename T>
    R get(S min, T max) {
        return get<R>(static_cast<R>(min), static_cast<R>(max));
    }
}

void testHomeWork8_08();
void testRandom();


namespace BallHeight {
    double getTowerHeight();
    constexpr double calculateBallHeight(double towerHeight, int seconds);
    void printBallHeight(double ballHeight, int seconds);
    double calculateAndPrintBallHeight(double towerHeight, int seconds);
    void testBallHeight();
}

namespace IsPrime {
    bool isPrime(int n);
    int modPow(int base, int exp, int mod);
    bool millerTest(int d, int n);
    bool isPrimeByMillerRabinAlg(int n, int k);
    void testPrimeList();
}

namespace GuessNumber {
    bool guessNumber(int guessCnt, int number);
    bool guessAgain();
    void playGame();
}
